package com.excilys.capicsoubank.controllers;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.tuple.Pair;
import org.joda.time.DateMidnight;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.util.Assert;

import com.excilys.capicsoubank.entities.Transaction;
import com.excilys.capicsoubank.entities.TransactionType;
import com.excilys.capicsoubank.services.AccountService;
import com.excilys.capicsoubank.services.TransactionService;

/**
 * Classe à hériter pour faire de la pagination sur des transactions.
 * 
 * @author "Grégory Coutant"
 * 
 */
public abstract class PaginationController {

	private static final int SIZE_PAGE = 10;

	@Autowired
	protected AccountService accountService;

	@Autowired
	protected TransactionService transactionService;

	/**
	 * Méthode pour remplir le modèle pour une pagination basique sur des
	 * transactions.
	 * 
	 * @param model
	 *            Le modèle à remplir
	 * @param accountId
	 *            L'id du compte à utiliser
	 * @param year
	 *            L'année à utiliser
	 * @param month
	 *            Le mois à utiliser
	 * @param page
	 *            La page à afficher
	 * @param types
	 *            Les types de transactions à récupérer
	 */
	protected void paginationController(Model model, int accountId, int year,
			int month, int page, TransactionType... types) {

		Assert.isTrue(transactionService.isInHistory(year, month));

		model.addAttribute("account", accountService.getAccountById(accountId));

		Pair<List<Transaction>, Long> pairTransactions = transactionService
				.getTransactionByAccountByYearByMonthByTypeWithPagination(
						accountId, year, month, types, page, SIZE_PAGE);

		model.addAttribute("transactions", pairTransactions.getLeft());
		model.addAttribute(
				"nbPages",
				(int) Math.ceil(pairTransactions.getRight()
						/ (double) SIZE_PAGE));
		model.addAttribute("currentPage", page);

		model.addAttribute("selectedYear", year);
		model.addAttribute("selectedMonth", month);

		storeHistory(model);
	}

	/**
	 * Permet d'obtenir la date de début d'un mois.
	 * 
	 * @param year
	 *            L'année voulue
	 * @param month
	 *            Le mois voulu
	 * @return La date
	 */
	protected DateTime getFirstDayOfMonth(int year, int month) {
		return new DateMidnight(year, month, 1).toDateTime();
	}

	/**
	 * Permet d'obtenir la date de fin de mois.
	 * 
	 * @param year
	 *            L'année voulue
	 * @param month
	 *            Le mois voulu
	 * @return La date
	 */
	protected DateTime getLastDayOfMonth(int year, int month) {
		return getFirstDayOfMonth(year, month).plusMonths(1).minusMillis(1);
	}

	/**
	 * Permet d'enregister dans le modèle les couples (année, mois) constituant
	 * l'historique.
	 * 
	 * @param model
	 *            Le modèle à remplir
	 */
	private void storeHistory(Model model) {
		List<Pair<Integer, Integer>> history = new ArrayList<Pair<Integer, Integer>>();

		DateTime now = DateTime.now();
		DateTime date = now.minusMonths(TransactionService.SIZE_HISTORY - 1);
		while (now.compareTo(date) >= 0) {
			history.add(Pair.of(date.year().get(), date.monthOfYear().get()));
			date = date.plusMonths(1);
		}

		model.addAttribute("history", history);
	}
}
